package utils;

import com.alibaba.fastjson.JSON;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import entry.Column;
import entry.Panel;
import entry.Panels;
import entry.PrintElements;
import entry.options.*;
import enums.BorderEnums;
import enums.OptionsTextTypeEnums;
import enums.TextAlignEnums;
import enums.TextVerticalAlignEnums;
import lombok.Data;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author LS
 * @Date 2023/4/23 11:41
 * @Description
 **/

public class HiPrintItextUtils {

    // PDF文档
    private Document document;

    // PDF结构
    private Panels panels;

    // 用于保存数据所需内部类
    private UtilData utilData;

    private PdfWriter pdfWriter;

    // 毫米与像素转换单位
    private final double mmToPx = 2.83;



    public HiPrintItextUtils(String json) throws FileNotFoundException {
        this.panels = getPanels(json);
        Panel panel = panels.getPanels().get(0);
        Rectangle pageSize = new Rectangle((float) (panel.getWidth() * mmToPx), (float) (panel.getHeight() * mmToPx));
        // 创建指定大小的页面
        document = new Document(pageSize);
    }

    @Data
    public static class UtilData {
        // 文本框绑定的字段 Map<'fieldKey', 'filedValue'>
        private Map<String, String> fields = new HashMap<>();

        // 每个表格对应的数据 Map<'tableKey', List<Map<'headerKey','fieldValue'>>> 若无headerKey兼容headerName
        private Map<String, List<Map<String, String>>> tableData = new HashMap<>();
    }

    public void setUtilData(UtilData utilData){
        this.utilData = utilData;
    }

    private Panels getPanels(String json){
        return JSON.parseObject(json, Panels.class);
    }

    /**
     * 创建新的页面
     */
    private void createPage(){
        document.newPage();
    }

    /**
     * 保存
     * @param filePath
     * @throws IOException
     */
    public void save(String filePath) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(filePath);
        try {
            // 构建返回流
            pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
            document.open();
            for (Panel panel : panels.getPanels()) {
                createPage();
                // 创建页面
                List<PrintElements> printElements = panel.getPrintElements();
                for (PrintElements printElement : printElements) {
                    dealOptions(printElement);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            document.close();
            fileOutputStream.close();
        }
    }

    /**
     * 处理Options结构，根据不同的Options生成不同的PDF元素
     * @param printElement
     */
    private void dealOptions(PrintElements printElement) throws Exception {
        Options options = printElement.getOptions();
        double left = options.getLeft();
        double top = options.getTop();
        double height = options.getHeight();
        double width = options.getWidth();
        // 获取Position打印位置
        Rectangle2D.Double position = new Rectangle2D.Double(left, top, width, height);
        if (options instanceof TextOptions){
            TextOptions textOptions = (TextOptions) options;
            OptionsTextTypeEnums textType = textOptions.getTextType();
            // 若传入字段不为空，需要通过数据字段获取值
            if (OptionsTextTypeEnums.TEXT.equals(textType)){
                // 无字段名时，绘制text
                if (textOptions.getField() != null){
                    createTextBoxField(textOptions, position);
                }else {
                    // 绘制字符串
                    createString(textOptions, position);
                }
            }else if (OptionsTextTypeEnums.BARCODE.equals(textType)){
                double barcodeHeight = height + textOptions.getFontSize() + 1;
                Rectangle2D.Double barcodePosition = new Rectangle2D.Double(left, top, width, barcodeHeight);
                createBarcode(textOptions, barcodePosition);
            }else if (OptionsTextTypeEnums.QRCODE.equals(textType)){
                createQrcode(textOptions, position);
            }else {
                // 不是有效枚举，跳过插入元素 todo doLog
            }
        }else if (options instanceof LongTextOptions){
            LongTextOptions longTextOptions = (LongTextOptions) options;
            createLongText(longTextOptions, position);
        }else if (options instanceof TableOptions){
            // todo 根据绘制方式区分绘制方式，
            //  1、表格数据大于表格大小时，复制当前页面所有数据，另起一页
            //  2、表格数据往后推并且是否重复表头
            TableOptions tableOptions = (TableOptions) options;
            createTable(tableOptions, position);
            // 后置绘制，根据不同的方式绘制页面
//            addPageTableCache(tableOptions, position);
        }else if (options instanceof ImageOptions){
            ImageOptions imageOptions = (ImageOptions) options;
            createImage(imageOptions, position);
        }else if (options instanceof  GraphicalOptions){
            createGraph(printElement, position);
        }else {
            throw new RuntimeException("无效元素");
        }
//        // 不为表格类型的打印数据进行缓存
//        if (! (options instanceof TableOptions)){
//            // 加入打印缓存
//            addPrintElementsPageCache(printElement);
//        }
    }

    private void createGraph(PrintElements printElement, Rectangle2D.Double position) {
    }

    private void createImage(ImageOptions imageOptions, Rectangle2D.Double position) {
    }

    /**
     * 创建表格
     * @param tableOptions
     * @param position
     */
    private void createTable(TableOptions tableOptions, Rectangle2D.Double position) throws IOException, DocumentException {
        List<Column> columns = tableOptions.getColumns().get(0);
        // 获取每个表格的宽度
        float[] columnWidthArray = new float[columns.size()];
        for (int i = 0; i < columns.size(); i++) {
            columnWidthArray[i] = columns.get(i).getWidth().floatValue();
        }
        // 创建表格，设定每列的宽度
        PdfPTable table = new PdfPTable(columnWidthArray);
        // 设定第一行为表头
        table.setHeaderRows(tableOptions.getColumns().size());
        // 表格总宽度
        table.setTotalWidth((float) tableOptions.getWidth());
        // 锁定宽度
        table.setLockedWidth(true);
        // todo 表格边框
//        getBorder(tableOptions.getTableHeaderBorder());
        // 表头字体
        Font tableHeaderFont = getFont(tableOptions.getFontFamily(), (int) tableOptions.getTableHeaderFontSize(), tableOptions.getTableHeaderFontWeight());
        // 表头背景色
        BaseColor tableHeaderBackGroundColor = hex2RGB(tableOptions.getTableHeaderBackground(), new Color(223, 223, 223));
        // 表体字体
        Font tableBodyFont = getFont(tableOptions.getFontFamily(), tableOptions.getFontSize(), null);
        table.getDefaultCell().setHorizontalAlignment(getHorizontalAlignment(tableOptions.getTextAlign()));
        table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
        // 文字左右对齐，默认使用居中对齐
        // 设置表头行高
        float headerCellHeight = 0;
        if (tableOptions.getTableHeaderRowHeight() >= 0){
            headerCellHeight = (float) tableOptions.getTableHeaderRowHeight();
        }
        // 设置表体行高
        float bodyCellHeight = 0;
        if (tableOptions.getTableBodyRowHeight() >= 0){
            bodyCellHeight = (float) tableOptions.getTableBodyRowHeight();
        }
        // 循环表头
        for (Column column : columns) {
            PdfPCell headerCell = new PdfPCell();
            // 设置单元格跨行跨列
            headerCell.setColspan(column.getColspan());
            headerCell.setRowspan(column.getRowspan());
            // 设置单元格行高
            headerCell.setFixedHeight(headerCellHeight);
            // 背景色
            headerCell.setBackgroundColor(tableHeaderBackGroundColor);
            // 设置左右对齐
            headerCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
            // 设置上下对齐
            headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
            // 设置表头与字体
            headerCell.addElement(new Paragraph(column.getTitle(), tableHeaderFont));
            table.addCell(headerCell);
        }
        // 获取画布
        PdfContentByte canvas = pdfWriter.getDirectContent();
        table.writeSelectedRows(0, -1, (float) position.getX(), (float) position.getY(), canvas);
        document.add(table);
    }

    /**
     * 获取需要展示的边框
     * @param borderEnums
     * @return
     */
    private int getBorder(BorderEnums borderEnums) {
        if (borderEnums != null){
            if (BorderEnums.BOTTOM_BORDER.equals(borderEnums)) {
                return Rectangle.BOTTOM;
            }else if (BorderEnums.NO_BORDER.equals(borderEnums)){
                return Rectangle.NO_BORDER;
            }else if (BorderEnums.TOP_BORDER.equals(borderEnums)){
                return Rectangle.TOP;
            }else if (BorderEnums.BORDER.equals(borderEnums)){
                // todo
            }
        }
        return Rectangle.NO_BORDER;
    }

    private void createLongText(LongTextOptions longTextOptions, Rectangle2D.Double position) {
    }

    private void createQrcode(TextOptions textOptions, Rectangle2D.Double position) {
    }

    private void createBarcode(TextOptions textOptions, Rectangle2D.Double barcodePosition) {
    }

    private void createString(TextOptions textOptions, Rectangle2D.Double position) {

    }

    private void createTextBoxField(TextOptions textOptions, Rectangle2D.Double position) throws DocumentException, IOException {
        String title = textOptions.getTitle();
        String field = textOptions.getField();
        String value = null;
        if (utilData != null && utilData.getFields() != null && field != null){
            value = utilData.getFields().get(field);
        }
        StringBuilder elementValue = new StringBuilder(title);
        // 若传入值
        if (value != null && !value.isEmpty()){
            elementValue.append("：").append(value);
        }
        // 文字字体
        Font font = getFont(textOptions.getFontFamily(), (int) textOptions.getFontSize(), textOptions.getFontWeight());
        // 设置元素及元素位置

        Paragraph paragraph = new Paragraph(elementValue.toString(), font);
        // 文字对齐
        paragraph.setAlignment(getTextAlign(textOptions.getTextAlign()));
        document.add(paragraph);
    }

//    private PdfFont getFont() throws IOException {
//        return PdfFontFactory.createFont("/fonts/文鼎PL简报宋.ttf", PdfEncodings.UTF8, true, true);
//    }


    /**
     * 十六进制颜色转换为RGB颜色
     * @param hexStr
     * @param defaultColor
     * @return
     */
    private BaseColor hex2RGB(String hexStr, Color defaultColor){
        if(hexStr != null && !"".equals(hexStr) && hexStr.length() == 7){
            int R = Integer.valueOf(hexStr.substring( 1, 3 ), 16);
            int G = Integer.valueOf(hexStr.substring( 3, 5 ), 16);
            int B = Integer.valueOf(hexStr.substring( 5, 7 ), 16);
            return new BaseColor(R, G, B);
        }
        return new BaseColor(defaultColor.getRed(), defaultColor.getGreen(), defaultColor.getBlue(), defaultColor.getAlpha());
    }

    /**
     * 获取字体
     * @param fontFamily
     * @param fontSize
     * @param fontWidth
     * @return
     */
    private Font getFont(String fontFamily, int fontSize, String fontWidth) throws IOException, DocumentException {
        // todo itext默认字体不支持中文，需要使用ttf文件指定
        if (fontFamily == null || fontFamily.isEmpty()){
            fontFamily = "";
        }
        if (fontSize <= 0){
            fontSize = 12;
        }
        if (fontWidth == null || fontWidth.isEmpty()){
            fontWidth = "";
        }
        BaseFont baseFont = BaseFont.createFont("/fonts/文鼎PL简报宋.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        return new Font(baseFont, fontSize);
    }

    /**
     * 获取文字对齐
     * @param textAlignEnums
     * @return
     */
    private int getTextAlign(TextAlignEnums textAlignEnums){
        return getHorizontalAlignment(textAlignEnums);
    }

    /**
     * 获取左右对齐
     * @param textAlignEnums
     * @return
     */
    private int getHorizontalAlignment(TextAlignEnums textAlignEnums){
        if (textAlignEnums != null){
            if (TextAlignEnums.CENTER.equals(textAlignEnums)){
                return Element.ALIGN_CENTER;
            }else if (TextAlignEnums.JSUTIFY.equals(textAlignEnums)){
                return Element.ALIGN_JUSTIFIED;
            }else if (TextAlignEnums.LEFT.equals(textAlignEnums)){
                return Element.ALIGN_LEFT;
            }else if (TextAlignEnums.RIGHT.equals(textAlignEnums)){
                return Element.ALIGN_RIGHT;
            }
        }
        return Element.ALIGN_CENTER;
    }

    /**
     * 获取上下对齐
     * @param verticalAlignEnums
     * @return
     */
    private float getVerticalAlignment(TextVerticalAlignEnums verticalAlignEnums){
        if (verticalAlignEnums != null){
            if (TextVerticalAlignEnums.BOTTOM.equals(verticalAlignEnums)){
                return Element.ALIGN_BOTTOM;
            }else if (TextVerticalAlignEnums.TOP.equals(verticalAlignEnums)){
                return Element.ALIGN_TOP;
            }else if (TextVerticalAlignEnums.MIDDLE.equals(verticalAlignEnums)){
                return Element.ALIGN_MIDDLE;
            }
        }
        return Element.ALIGN_MIDDLE;
    }
}
